#include "stdafx.h"
#include "Interpreter.h"
#include "World.h"
#include <cctype>
#include <fstream>
#include <ios>
using namespace std;

CInterpreter::CInterpreter(string fileName):
    m_Io(fileName == "io")
{
    if (!m_Io)
    {
        m_in = ifstream(fileName);
    }
}

CInterpreter::~CInterpreter()
{
    m_in.close();
}

char CInterpreter::GetChar()
{
    if (m_Io)
    {
        return cin.get();
    }
    else
    {
        return m_in.get();
    }
}

void CInterpreter::Interpret()
{
    if ((!m_Io) && (!m_in.is_open()))
    {
        cout << "ERROR: Can't open file" << endl;
        return;
    }
    if (m_Io)
    {
        cout << "Ready for interpret." << endl;
    }
    else
    {
        cout << "Starting interpretation." << endl;
    }
    string lastWord;
    char ch;
    while ((ch = GetChar()) && (ch != EOF))
    {
        //cout << "(" << (int)ch << ")";
        if (!IsSemicolon(ch))
        {
            if (ch == 26)
            {
                break;
            }
            //if (!IsSpace(ch))
            {
                lastWord += ch;
            }
        }
        else
        {
            //cout << " " << lastWord.c_str() << endl;
            Process(lastWord);
            lastWord = "";
        }
    }
    Process(lastWord);
    cout << "End of interpretation." << endl;
}

bool CInterpreter::IsSemicolon(char ch)
{
    //return ((ch == ';') || (ch == '\n'));
    return ch == ';';
}

bool CInterpreter::IsSpace(char ch)
{
    //return ((ch == ';') || (ch == '\n'));
    return (ch == ' ') || (ch == '\n') || (ch == 10);
}

void CInterpreter::Process(string word)
{
    DeleteExtraFirstSpaces(word);
    if (word.size() == 0)
    {
        return;
    }
    cout << "INTERPRETED: <" << word << "> = ";
    string arg, command;
    WordType type = ValidateWord(word, arg, command);
    switch (type)
    {
    case WORD_INVALID:
        cout << "ERROR.";
        break;
    case WORD_ADD:
        cout << "ADD " << arg << ".";
        m_world.CreateDwarf(GetDwarfType(arg));
        break;
    case WORD_SELECT:
        cout << "SELECT " << arg << ".";
        m_world.SelectDwarf(atoi(arg.c_str()));
        break;
    case WORD_WHILE:
        cout << "WHILE " << arg << " DO " << command << ".";
        m_world.While(arg, command);
        break;
    case WORD_COMMAND:
        cout << "COMMAND " << command << ".";
        m_world.Command(command);
    }
    cout << endl;
}

WordType CInterpreter::ValidateWord(string word, string & returnArg, string & command)
{
    if (word.substr(0, 4) == "add(")
    {
        int rBracketPos = word.find(")");
        if (rBracketPos != word.size() - 1)
        {
            return WORD_INVALID;
        }
        if (GetDwarfType(word.substr(4, rBracketPos - 4)) != DWARF_NONE)
        {
            returnArg = word.substr(4, rBracketPos - 4);
            return WORD_ADD;
        }
    }
    else if (word.substr(0, 7) == "select(")
    {
        int rBracketPos = word.find(")");
        if (rBracketPos != word.size() - 1)
        {
            return WORD_INVALID;
        }
        string arg = word.substr(7, rBracketPos - 7);
        if ((IsNumber(arg)) && (atoi(arg.c_str()) >= 0))
        {
            returnArg = arg;
            return WORD_SELECT;
        }
    }
    else if (word.substr(0, 7) == "while (")
    {
        int rBracketPos = word.find(")");
        string condition = word.substr(7, rBracketPos - 7);
        if (m_world.IsValidCondition(condition))
        {
            if (word[rBracketPos + 1] != ' ')
            {
                return WORD_INVALID;
            }
            string com = word.substr(rBracketPos + 2, word.size() - rBracketPos - 1);
            if (ValidateWord(com, returnArg, command) != WORD_INVALID)
            {
                returnArg = condition;
                return WORD_WHILE;
            }
            else
            {
                return WORD_INVALID;
            }
        }
    }
    else if (m_world.IsValidCommand(word))
    {
        command = word;
        return WORD_COMMAND;
    }
    return WORD_INVALID;
}

bool CInterpreter::IsNumber(const std::string & s)
{
    std::string::const_iterator it = s.begin();
    while (it != s.end() && std::isdigit(*it)) ++it;
    return !s.empty() && it == s.end();
}

void CInterpreter::DeleteExtraFirstSpaces(string & str)
{
    if (!IsSpace(str[0]))
    {
        return;
    }
    int i = 0;
    while ((i < str.size()) && (IsSpace(str[i])))
    {
        ++i;
    }
    if (i > 0)
    {
        str.erase(str.begin(), str.begin() + i);
    }
}